"""
插件系统测试配置

为插件系统测试提供共享的fixtures和配置。
"""

import pytest
import tempfile
import shutil
from pathlib import Path
from unittest.mock import Mock, AsyncMock

from src.core.plugin import (
    PluginManager, PluginRegistry, PluginLoader, HookManager, PluginContext,
    Plugin, PluginState, PluginMetadata, ProcessorPlugin, ClassifierPlugin
)


@pytest.fixture
def temp_dir():
    """临时目录fixture"""
    temp_path = tempfile.mkdtemp()
    yield temp_path
    shutil.rmtree(temp_path, ignore_errors=True)


@pytest.fixture
def plugin_context(temp_dir):
    """插件上下文fixture"""
    return PluginContext(
        config_dir=temp_dir,
        data_dir=temp_dir,
        log_dir=temp_dir
    )


@pytest.fixture
def plugin_registry():
    """插件注册表fixture"""
    return PluginRegistry()


@pytest.fixture
def plugin_loader():
    """插件加载器fixture"""
    return PluginLoader()


@pytest.fixture
def hook_manager():
    """钩子管理器fixture"""
    return HookManager()


@pytest.fixture
def plugin_manager(plugin_context, plugin_registry, plugin_loader, hook_manager):
    """插件管理器fixture"""
    return PluginManager(
        context=plugin_context,
        registry=plugin_registry,
        loader=plugin_loader,
        hook_manager=hook_manager
    )


class MockPlugin(Plugin):
    """测试用模拟插件"""
    
    def __init__(self, name="mock_plugin", version="1.0.0", dependencies=None):
        super().__init__()
        self._name = name
        self._version = version
        self._dependencies = dependencies or []
        self._description = f"Mock plugin {name}"
        self._author = "Test Author"
        self.init_called = False
        self.destroy_called = False
    
    @property
    def name(self) -> str:
        return self._name
    
    @property
    def version(self) -> str:
        return self._version
    
    @property
    def description(self) -> str:
        return self._description
    
    @property
    def author(self) -> str:
        return self._author
    
    @property
    def dependencies(self) -> list:
        return self._dependencies
    
    async def on_init(self, ctx):
        """初始化回调"""
        self.init_called = True
        self.context = ctx
    
    async def on_destroy(self):
        """销毁回调"""
        self.destroy_called = True


class MockProcessorPlugin(ProcessorPlugin):
    """测试用处理器插件"""
    
    def __init__(self, name="mock_processor"):
        super().__init__()
        self._name = name
        self.processed_items = []
    
    @property
    def name(self) -> str:
        return self._name
    
    @property
    def version(self) -> str:
        return "1.0.0"
    
    async def process(self, input_data, **kwargs):
        """处理数据"""
        result = f"processed_{input_data}"
        self.processed_items.append(result)
        return result


class MockClassifierPlugin(ClassifierPlugin):
    """测试用分类器插件"""
    
    def __init__(self, name="mock_classifier", dependencies=None):
        super().__init__()
        self._name = name
        self._dependencies = dependencies or []
        self.classified_items = []
    
    @property
    def name(self) -> str:
        return self._name
    
    @property
    def version(self) -> str:
        return "1.0.0"
    
    @property
    def dependencies(self) -> list:
        return self._dependencies
    
    async def classify(self, input_data, **kwargs):
        """分类数据"""
        result = f"classified_{input_data}"
        self.classified_items.append(result)
        return result


@pytest.fixture
def mock_plugin():
    """模拟插件fixture"""
    return MockPlugin()


@pytest.fixture
def mock_processor_plugin():
    """模拟处理器插件fixture"""
    return MockProcessorPlugin()


@pytest.fixture
def mock_classifier_plugin():
    """模拟分类器插件fixture"""
    return MockClassifierPlugin()


@pytest.fixture
def plugin_with_dependencies():
    """有依赖的插件fixture"""
    return MockPlugin(
        name="dependent_plugin",
        dependencies=["dependency1", "dependency2"]
    )


@pytest.fixture
def plugin_metadata():
    """插件元数据fixture"""
    return PluginMetadata(
        name="test_plugin",
        version="1.0.0",
        description="Test plugin for unit testing",
        author="Test Author",
        dependencies=["dep1", "dep2"],
        category="testing",
        tags=["test", "mock"],
        config_schema={
            "param1": {"type": "string", "default": "default_value"},
            "param2": {"type": "integer", "default": 10}
        },
        default_config={
            "param1": "default_value",
            "param2": 10
        }
    )


@pytest.fixture
def sample_plugin_file(temp_dir):
    """示例插件文件fixture"""
    plugin_content = '''
from src.core.plugin.base import Plugin

class SamplePlugin(Plugin):
    @property
    def name(self):
        return "sample_plugin"
    
    @property
    def version(self):
        return "1.0.0"
    
    @property
    def description(self):
        return "Sample plugin for testing"
    
    @property
    def author(self):
        return "Test Author"
    
    async def on_init(self, ctx):
        self.initialized = True

def create_plugin():
    return SamplePlugin()
'''
    
    plugin_file = Path(temp_dir) / "sample_plugin.py"
    plugin_file.write_text(plugin_content)
    return plugin_file


@pytest.fixture
def plugin_directory(temp_dir):
    """插件目录fixture"""
    plugin_dir = Path(temp_dir) / "plugins"
    plugin_dir.mkdir()
    
    # 创建多个插件文件
    plugins = [
        ("plugin_a.py", "PluginA"),
        ("plugin_b.py", "PluginB"),
        ("plugin_c.py", "PluginC")
    ]
    
    for filename, class_name in plugins:
        plugin_content = f'''
from src.core.plugin.base import Plugin

class {class_name}(Plugin):
    @property
    def name(self):
        return "{filename[:-3]}"
    
    @property
    def version(self):
        return "1.0.0"

def create_plugin():
    return {class_name}()
'''
        (plugin_dir / filename).write_text(plugin_content)
    
    return plugin_dir


@pytest.fixture
def mock_hook_callback():
    """模拟钩子回调fixture"""
    return Mock(return_value="hook_result")


@pytest.fixture
def async_mock_hook_callback():
    """异步模拟钩子回调fixture"""
    return AsyncMock(return_value="async_hook_result")


@pytest.fixture
def plugin_config():
    """插件配置fixture"""
    return {
        "enabled": True,
        "log_level": "INFO",
        "max_workers": 4,
        "timeout": 30,
        "custom_settings": {
            "feature_a": True,
            "feature_b": False,
            "threshold": 0.8
        }
    }


@pytest.fixture
def plugin_dependencies_graph():
    """插件依赖图fixture"""
    return {
        "plugin_a": [],
        "plugin_b": ["plugin_a"],
        "plugin_c": ["plugin_a"],
        "plugin_d": ["plugin_b", "plugin_c"],
        "plugin_e": ["plugin_d"]
    }


@pytest.fixture(autouse=True)
def cleanup_plugin_state():
    """自动清理插件状态"""
    yield
    # 测试后清理全局状态
    # 这里可以添加清理逻辑，如重置全局变量等


class PluginTestHelper:
    """插件测试辅助类"""
    
    @staticmethod
    def create_plugin_with_metadata(name, version="1.0.0", dependencies=None):
        """创建带元数据的插件"""
        plugin = MockPlugin(name=name, version=version, dependencies=dependencies)
        metadata = PluginMetadata(
            name=name,
            version=version,
            dependencies=dependencies or [],
            description=f"Test plugin {name}",
            author="Test Author"
        )
        plugin.metadata = metadata
        return plugin, metadata
    
    @staticmethod
    def create_plugin_chain(names):
        """创建插件链（每个插件依赖前一个）"""
        plugins = []
        for i, name in enumerate(names):
            dependencies = [names[i-1]] if i > 0 else []
            plugin, metadata = PluginTestHelper.create_plugin_with_metadata(
                name, dependencies=dependencies
            )
            plugins.append((plugin, metadata))
        return plugins
    
    @staticmethod
    async def register_and_init_plugins(manager, plugins):
        """注册并初始化插件列表"""
        # 注册所有插件
        for plugin, metadata in plugins:
            manager.register_plugin(plugin, metadata)
        
        # 按依赖顺序初始化
        plugin_names = [plugin.name for plugin, _ in plugins]
        load_order = manager.registry.resolve_load_order(plugin_names)
        
        for plugin_name in load_order:
            await manager.initialize_plugin(plugin_name)
        
        return load_order


@pytest.fixture
def plugin_test_helper():
    """插件测试辅助fixture"""
    return PluginTestHelper
